﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Quail
{
    /// <summary>
    /// Wraps access to a collection of RADIO controls
    /// </summary>
    public class WebRadioGroup : WebInput, IWebControlWithItems
    {
        private List<WebInput> _members;

        /// <summary>
        /// Initializes a new instance of the <see cref="WebRadioGroup"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="selector">The jQuery selector. </param>
        public WebRadioGroup(WebControlContainer container, string selector)
            : base(container, selector)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WebRadioGroup"/> class.
        /// </summary>
        /// <param name="control">The control to copy from. </param>
        public WebRadioGroup(WebControl control)
            : base(control)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WebRadioGroup"/> class.
        /// </summary>
        public WebRadioGroup()
        {
        }

        /// <summary>
        /// Gets or sets the selected radio item control
        /// </summary>
        public WebInput SelectedControl
        {
            get
            {
                var members = GetMembers();

                foreach (var member in members)
                {
                    if (member.Checked)
                        return member;
                }

                return null;
            }

            set
            {
                Value = value.Value;
            }
        }

        /// <summary>
        /// Gets or sets the selected radio group item
        /// </summary>
        public override string Value
        {
            get
            {
                var member = SelectedControl;

                if (member != null)
                    return member.Value;

                return string.Empty;
            }

            set
            {
                var task = BeginTask("Set Value");
                task.AddAttribute("Value", value);
                try
                {
                    var control = Page.GetRadioGroup( string.Format( "{0}[value={1}]",Selector, value ) );
                    control.Checked = true;
                    task.Finish();
                }
                catch (Exception e)
                {
                    task.Finish(e);
                    throw;
                }
            }
        }

        /// <summary>
        /// Gets or sets Label.
        /// </summary>
        public override string Label
        {
            get
            {
                var member = SelectedControl;

                if (member == null)
                    return string.Empty;

                var labelctrl = member.LabelControl;
                if (labelctrl.Exists)
                    return labelctrl.InnerText;

                return string.Empty;
            }

            set
            {
                var task = BeginTask("Set Label");
                task.AddAttribute("Label", value);
                try
                {
                    foreach (var member in GetMembers())
                    {
                        var labelctrl = member.LabelControl;

                        if (labelctrl.Exists && labelctrl.InnerText == value)
                        {
                            member.Checked = true;
                            task.Finish();
                            return;
                        }
                    }

                    throw new WebControlException(this, "Specified label not found in radio group: " + value);
                }
                catch (Exception e)
                {
                    task.Finish(e);
                    throw;
                }
            }
        }

        /// <summary>
        /// Gets a count of all the items in the control  (Labels.Count == Values.Count == CountItems)
        /// </summary>
        public int ItemCount
        {
            get
            {
                return GetMembers().Count;
            }
        }

        /// <summary>
        /// Gets a list of all the labels for this radio group
        /// </summary>
        public string[] Labels
        {
            get
            {
                var members = GetMembers();
                var result = new string[members.Count];

                for (var index = 0; index < members.Count; index++)
                {
                    var member = members[index];
                    var labelctrl = member.LabelControl;

                    result[index] = labelctrl.Exists ? labelctrl.InnerText : string.Empty;
                }

                return result;
            }
        }

        /// <summary>
        /// Gets a list of all the values for this radio group
        /// </summary>
        public string[] Values
        {
            get
            {
                var members = GetMembers();
                var result = new string[members.Count];
                for (int index = 0; index < members.Count; index++)
                    result[index] = members[index].Value;

                return result;
            }
        }

        /// <summary>
        /// Gets or sets the selected radio index
        /// </summary>
        public int SelectedIndex
        {
            get
            {
                var control = SelectedControl;

                return control != null ? control.Index : -1;
            }

            set
            {
                GetMembers()[value].Checked = true;
            }
        }

        /// <summary>
        /// Gets the label for a specific item index
        /// </summary>
        /// <param name="index">the index to get</param>
        /// <returns>the label value</returns>
        public string GetLabel(int index)
        {
            var members = GetMembers();
            return members[index].Label;
        }

        /// <summary>
        /// Gets the value for a specific item index
        /// </summary>
        /// <param name="index">the index to get</param>
        /// <returns>the value of the item</returns>
        public string GetValue(int index)
        {
            var members = GetMembers();
            return members[index].Value;
        }

        /// <summary>
        /// Checks to see if a value is represented in the radio group
        /// </summary>
        /// <param name="value">The value to search for</param>
        /// <returns>True if the value is in the group</returns>
        public bool ValueExists(string value)
        {
            foreach (var member in GetMembers())
            {
                if (member.Value == value)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// Checks to see if a label is represented in the radio group
        /// </summary>
        /// <param name="label">The label to search for</param>
        /// <returns>True if the label is in the group</returns>
        public bool LabelExists(string label)
        {
            return Labels.Any(l => l == label);
        }

        /// <summary>
        /// A list of controls for the group of RADIO controls.
        /// This list is evaluated only once - reset it using ResetMembers method.
        /// </summary>
        /// <returns>The list of controls</returns>
        public List<WebInput> GetMembers()
        {
            if (_members == null)
                _members = Page.GetControls<WebInput>(Selector);

            return _members;
        }

        /// <summary>
        /// Resets the list of members for the RADIO group
        /// </summary>
        public void ResetMembers()
        {
            _members = null;
        }

		/// <summary>
		/// Selects a random item from the radio group
		/// </summary>
		/// <param name="selectDifferentValue">If the value should be different than the currently selected value</param>
		public void SelectRandomValue(bool selectDifferentValue)
		{
			if (selectDifferentValue)
			{
				var currentlySelected = Value;

				do
				{
					SelectRandomValue();
				}
				while (Value == currentlySelected);
			}
			else
			{
				SelectRandomValue();
			}
		}

    	/// <summary>
        /// Selects a random item from the radio group
        /// </summary>
        public void SelectRandomValue()
        {
            var task = BeginTask("SelectRandomValue");
            try
            {
                var mems = GetMembers();

                if (mems.Count == 0)
                    throw new WebControlException(this, "The radio group [" + Selector + "] doesn't have any members to select!");

                var idx = new Random().Next(0, mems.Count);
                mems[idx].Checked = true;

                task.AddAttribute("Label", mems[idx].LabelControl.InnerText);
                task.AddAttribute("Value", mems[idx].Value);
                task.Finish();
            }
            catch (Exception e)
            {
                task.Finish(e);
                throw;
            }
        }

        /// <summary>
        /// Clears the radio group from any selected items (WARNING: may cause problems on pages that expect OnClick!)
        /// </summary>
		public override void Clear()
		{
            var task = BeginTask("WebRadioGroup.Clear");
            try
            {
                foreach (var member in GetMembers())
                {
                    if (member.Checked)
                    {
                        Browser.SeleniumInterface.Uncheck(member.Locator);
                    }
                }
                
                task.Finish();
            }
            catch (Exception e)
            {
                task.Finish(e);
                throw;
            }
		}
    }
}
